﻿using System;
using System.Collections.Generic;
using System.Text;
using PetaPoco.NetCore;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using Pomelo.Data.MySql;
using AMInstantMessagingService;

namespace BaseSimpleDao
{
    /// <summary>
    /// 数据库连接分享组件
    /// </summary>
    public class DataBaseSharedConnection : IDisposable
    {
        private Database _Database = null;

        public DataBaseSharedConnection(Database db)
        {
            _Database = db;

            if (_Database != null)
                _Database.OpenSharedConnection();
        }

        public void Dispose()
        {
            if (_Database != null)
                _Database.CloseSharedConnection();
        }
    }

    public class DataBaseShare
    {
        protected Dictionary<string, Database> ConnectionString2Database = new Dictionary<string, Database>();

        private DataBaseShare() { }

        private static DataBaseShare _DataBaseShare = null;
        private static object _Lock = new object();

        /// <summary>
        /// 获取数据实例
        /// </summary>
        /// <returns></returns>
        public static DataBaseShare GetInstance()
        {
            if (_DataBaseShare == null) lock (_Lock) if (_DataBaseShare == null)
                        _DataBaseShare = new DataBaseShare();

            return _DataBaseShare;
        }

        /// <summary>
        /// 获取共享数据库
        /// </summary>
        /// <param name="DatabaseConnectionString"></param>
        /// <returns></returns>
        public Database GetShareDataBase(string DatabaseConnectionString)
        {
            if (!ConnectionString2Database.ContainsKey(DatabaseConnectionString)) lock (this) if (!ConnectionString2Database.ContainsKey(DatabaseConnectionString))
                        ConnectionString2Database[DatabaseConnectionString] = new Database(DataConnectionHelper.GetDbConnection(DatabaseConnectionString));

            return ConnectionString2Database[DatabaseConnectionString];
        }
    }

    public static class DataConnectionHelper
    {
        public static IDbConnection GetDbConnection(string conn)
        {
            if (string.IsNullOrEmpty(conn))
                return null;

            Dictionary<string, string> conn_mapping = new Dictionary<string, string>();
            foreach (var item in conn.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) ?? new string[] { })
            {
                var values = item.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
                if (values.Length != 2)
                    continue;

                conn_mapping[values[0]] = values[1];
            }

            string conn_string = string.Join(";", conn_mapping.Where(n => n.Key != "DBType").Select(n => string.Format("{0}={1}", n.Key, n.Value)));

            Dictionary<string, Type> typename2type = new Dictionary<string, Type>
            {
                { "SqlServer", typeof(SqlConnection) },
                { "MySql", typeof(MySqlConnection) },
            };

            if (conn_mapping.ContainsKey("DBType") && typename2type.ContainsKey(conn_mapping["DBType"]))
            {
                var type = typename2type[conn_mapping["DBType"]];
                var connection = (IDbConnection)type.Assembly.CreateInstance(type.FullName);

                connection.ConnectionString = conn_string;

                return connection;
            }
            else
            {
                return new SqlConnection(conn_string);
            }
        }
    }


    /// <summary>
    /// 基础数据提供类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class BaseProvider<T>
        where T : BaseModel
    {
        /// <summary>
        /// 数据表
        /// </summary>
        protected static Database _Database = null;

        /// <summary>
        /// 数据库操作
        /// </summary>
        public virtual Database Database
        {
            get
            {
                if (_Database == null) lock (this) if (_Database == null)
                            _Database = DataBaseShare.GetInstance().GetShareDataBase(DatabaseConnectionString);

                return _Database;
            }
        }

        /// <summary>
        /// 配置文件中默认的数据库连接字符串名
        /// </summary>
        public virtual string DatabaseConnectionString
        {
            get { return ConfigurationManager.ConnectionStrings["ConnectionString"]; }
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public virtual bool Add(T t)
        {
            object code = 0;

            using (new DataBaseSharedConnection(_Database))
                code = Database.Insert(t);

            return (long)code > 0;
        }

        /// <summary>
        /// 添加列表数据
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public int AddList(List<T> list)
        {
            int count = 0;

            using (new DataBaseSharedConnection(_Database))
            {
                foreach (var item in list)
                {
                    if (Add(item))
                        ++count;
                }
            }

            return count;
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public virtual int Remove(T t)
        {
            using (new DataBaseSharedConnection(_Database))
                return Database.Delete(t);
        }

        /// <summary>
        /// 根据筛选列表删除
        /// </summary>
        /// <param name="filters"></param>
        /// <returns></returns>
        public virtual int Remove(IEnumerable<BaseFilter> filters)
        {
            Sql sql = Sql.Builder;
            sql.Append(string.Format("DELETE FROM {0}", BaseHelper.GetTableName(typeof(T))));
            BaseHelper.SqlLinkFilter(sql, filters);

            using (new DataBaseSharedConnection(_Database))
                return Database.Execute(sql);
        }

        /// <summary>
        /// 感觉筛选获取具体对象Id
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public long GetItemIdByFilter(string name, object value)
        {
            using (new DataBaseSharedConnection(_Database))
                return GetFirstOrDefaultId(new List<BaseFilter> { { name, "=", value } });
        }

        /// <summary>
        /// 根据筛选获取具体对象
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public T GetItemByFilter(string name, object value)
        {
            using (new DataBaseSharedConnection(_Database))
                return GetFirstOrDefault(new List<BaseFilter> { { name, "=", value } });
        }

        /// <summary>
        /// 根据Id删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual int RemoveById(long id)
        {
            Sql sql = Sql.Builder;
            sql.Append(string.Format("DELETE FROM {0}", BaseHelper.GetTableName(typeof(T))));
            sql.Where("Id = @0", id);

            using (new DataBaseSharedConnection(_Database))
                return Database.Execute(sql);
        }

        /// <summary>
        /// 更新对象
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public virtual int Update(T t)
        {
            using (new DataBaseSharedConnection(_Database))
                return Database.Update(t);
        }

        /// <summary>
        /// 更新列表
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public virtual int UpdateList(IEnumerable<T> list)
        {
            var sum = 0;

            using (new DataBaseSharedConnection(_Database))
            {
                foreach (var item in list)
                    sum += Database.Update(item);
            }

            return sum;
        }

        /// <summary>
        /// 根据简单的筛选器获取列表数据
        /// </summary>
        /// <param name="name">列名</param>
        /// <param name="value">列值</param>
        /// <param name="orders">排序依据</param>
        /// <returns></returns>
        public virtual IEnumerable<T> GetListBySingleFilter(string name, object value, IEnumerable<BaseOrder> orders = null)
        {
            using (new DataBaseSharedConnection(_Database))
                return GetListByFilter(new List<BaseFilter> { { name, "=", value } }, orders);
        }

        /// <summary>
        /// 获取前N条数据
        /// </summary>
        /// <param name="count"></param>
        /// <param name="filters"></param>
        /// <param name="orders"></param>
        /// <returns></returns>
        public virtual IEnumerable<T> GetTop(int count, IEnumerable<BaseFilter> filters = null, IEnumerable<BaseOrder> orders = null)
        {
            Sql sql = Sql.Builder;
            sql.Select(string.Format("Top {0} *", count)).From(BaseHelper.GetTableName(typeof(T)));
            BaseHelper.SqlLinkFilter(sql, filters);
            BaseHelper.SqlLinkOrder(sql, orders);

            using (new DataBaseSharedConnection(_Database))
                return Database.Fetch<T>(sql);
        }

        /// <summary>
        /// 获取全部
        /// </summary>
        /// <param name="orders">排序依据</param>
        /// <returns></returns>
        public virtual IEnumerable<T> GetAll(IEnumerable<BaseOrder> orders = null)
        {
            Sql sql = Sql.Builder;
            sql.Select("*").From(BaseHelper.GetTableName(typeof(T)));
            BaseHelper.SqlLinkOrder(sql, orders);

            using (new DataBaseSharedConnection(_Database))
                return Database.Fetch<T>(sql);
        }

        /// <summary>
        /// 根据Id获取具体对象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual T GetItemById(long id)
        {
            Sql sql = Sql.Builder;
            sql.Select("*").From(BaseHelper.GetTableName(typeof(T)));
            sql.Where("Id = @0", id);

            using (new DataBaseSharedConnection(_Database))
                return Database.FirstOrDefault<T>(sql);
        }

        /// <summary>
        /// 根据Id列表获取列表对象
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="orders"></param>
        /// <returns></returns>
        public virtual IEnumerable<T> GetListByIds(IEnumerable<long> ids, IEnumerable<BaseOrder> orders = null)
        {
            Sql sql = Sql.Builder;
            sql.Select("*").From(BaseHelper.GetTableName(typeof(T)));

            sql.Where(string.Format("Id IN ({0})", string.Join(",", ids)));

            BaseHelper.SqlLinkOrder(sql, orders);

            using (new DataBaseSharedConnection(_Database))
                return Database.Fetch<T>(sql);
        }

        /// <summary>
        /// 根据筛选器获取列表
        /// </summary>
        /// <param name="filters"></param>
        /// <param name="orders"></param>
        /// <returns></returns>
        public virtual IEnumerable<T> GetListByFilter(IEnumerable<BaseFilter> filters, IEnumerable<BaseOrder> orders = null)
        {
            Sql sql = Sql.Builder;
            sql.Select("*").From(BaseHelper.GetTableName(typeof(T)));
            BaseHelper.SqlLinkFilter(sql, filters);
            BaseHelper.SqlLinkOrder(sql, orders);

            using (new DataBaseSharedConnection(_Database))
                return Database.Fetch<T>(sql);
        }

        /// <summary>
        /// 获取第一个或者默认的对象
        /// </summary>
        /// <param name="filters"></param>
        /// <param name="orders"></param>
        /// <returns></returns>
        public virtual T GetFirstOrDefault(IEnumerable<BaseFilter> filters, IEnumerable<BaseOrder> orders = null)
        {
            Sql sql = Sql.Builder;
            sql.Select("Top 1 *").From(BaseHelper.GetTableName(typeof(T)));
            BaseHelper.SqlLinkFilter(sql, filters);
            BaseHelper.SqlLinkOrder(sql, orders);

            using (new DataBaseSharedConnection(_Database))
                return Database.FirstOrDefault<T>(sql);
        }

        /// <summary>
        /// 获取分页列表数据
        /// </summary>
        /// <param name="page">页码数</param>
        /// <param name="itemsPerPage">每页数量</param>
        /// <param name="filters"></param>
        /// <param name="orders"></param>
        /// <returns></returns>
        public virtual Page<T> GetPage(int page, int itemsPerPage, IEnumerable<BaseFilter> filters, IEnumerable<BaseOrder> orders = null)
        {
            Sql sql = Sql.Builder;
            sql.Select("*").From(BaseHelper.GetTableName(typeof(T)));
            BaseHelper.SqlLinkFilter(sql, filters);
            BaseHelper.SqlLinkOrder(sql, orders);

            using (new DataBaseSharedConnection(_Database))
                return Database.Page<T>(page, itemsPerPage, sql);
        }

        /// <summary>
        /// 根据Id获取分页Id
        /// </summary>
        /// <param name="id"></param>
        /// <param name="itemsPerPage"></param>
        /// <param name="filters"></param>
        /// <param name="orders"></param>
        /// <returns></returns>
        public virtual int GetPageIndex(long id, int itemsPerPage, IEnumerable<BaseFilter> filters, IEnumerable<BaseOrder> orders)
        {
            Sql sql = Sql.Builder;
            sql.Select("Id").From(BaseHelper.GetTableName(typeof(T)));
            BaseHelper.SqlLinkFilter(sql, filters);
            BaseHelper.SqlLinkOrder(sql, orders);

            List<long> ids = null;
            using (new DataBaseSharedConnection(_Database))
                ids = Database.Fetch<long>(sql);

            if (!ids.Contains(id))
                return 1;

            return ids.IndexOf(id) / itemsPerPage + 1;
        }


        /// <summary>
        /// 获取符合筛选器的数据数量
        /// </summary>
        /// <param name="filters">筛选器</param>
        /// <returns></returns>
        public virtual int GetCount(IEnumerable<BaseFilter> filters)
        {
            Sql sql = Sql.Builder;
            sql.Select("COUNT(*)").From(BaseHelper.GetTableName(typeof(T)));
            BaseHelper.SqlLinkFilter(sql, filters);

            using (new DataBaseSharedConnection(_Database))
                return Database.FirstOrDefault<int>(sql);
        }

        /// <summary>
        /// 获取数据Id列表
        /// </summary>
        /// <param name="filters">筛选器</param>
        /// <param name="orders">排序依据</param>
        /// <returns></returns>
        public virtual IEnumerable<long> GetItemIdList(IEnumerable<BaseFilter> filters, IEnumerable<BaseOrder> orders = null)
        {
            Sql sql = Sql.Builder;
            sql.Select("Id").From(BaseHelper.GetTableName(typeof(T)));
            BaseHelper.SqlLinkFilter(sql, filters);
            BaseHelper.SqlLinkOrder(sql, orders);

            using (new DataBaseSharedConnection(_Database))
                return Database.Fetch<long>(sql);
        }

        /// <summary>
        /// 获取前N条数据Id
        /// </summary>
        /// <param name="count">数量限制</param>
        /// <param name="filters">筛选器</param>
        /// <param name="orders">排序依据</param>
        /// <returns></returns>
        public IEnumerable<long> GetTopIdList(int count, IEnumerable<BaseFilter> filters, IEnumerable<BaseOrder> orders = null)
        {
            Sql sql = Sql.Builder;
            sql.Select(string.Format("Top {0} Id", count)).From(BaseHelper.GetTableName(typeof(T)));
            BaseHelper.SqlLinkFilter(sql, filters);
            BaseHelper.SqlLinkOrder(sql, orders);

            using (new DataBaseSharedConnection(_Database))
                return Database.Fetch<long>(sql);
        }

        /// <summary>
        /// 获取第一个或者默认的对象Id
        /// </summary>
        /// <param name="filters">筛选器</param>
        /// <param name="orders">排序依据</param>
        /// <returns></returns>
        public long GetFirstOrDefaultId(IEnumerable<BaseFilter> filters, IEnumerable<BaseOrder> orders = null)
        {
            Sql sql = Sql.Builder;
            sql.Select("Top 1 Id").From(BaseHelper.GetTableName(typeof(T)));
            BaseHelper.SqlLinkFilter(sql, filters);
            BaseHelper.SqlLinkOrder(sql, orders);

            using (new DataBaseSharedConnection(_Database))
                return Database.FirstOrDefault<long>(sql);
        }
    }
}
